﻿using System;
using System.Net;
using Polenter.Serialization;
using Polenter.Serialization.Core;
using Polenter.Serialization.Advanced;
using System.IO;
using System.Text;
using AbstraX;
using Polenter.Serialization.Advanced.Serializing;

namespace Hydra.Shell.Utilities
{
    internal class TypeNameConverter : ITypeNameConverter
    {
        public Type ConvertToType(string typeName)
        {
            if (typeName != null)
            {
                return Type.GetType(typeName);
            }
            else
            {
                return null;
            }
        }

        public string ConvertToTypeName(Type type)
        {
            return type.FullName;
        }
    }

    internal static class PackageHelper
    {
        internal static string GetObjectBytes(object obj)
        {
            var settings = new SharpSerializerXmlSettings
            {
                AdvancedSettings = new AdvancedSharpSerializerXmlSettings
                {
                    TypeNameConverter = new TypeNameConverter()
                },

                IncludeAssemblyVersionInTypeName = false,
                IncludeCultureInTypeName = false,
                IncludePublicKeyTokenInTypeName = false
            };

            var serializer = new SharpSerializer(settings);
            var stream = new MemoryStream();
            var text = string.Empty;
            var bytes = (byte[])null;

            serializer.Serialize(obj, stream);

            stream.Seek(0, SeekOrigin.Begin);

            bytes = new byte[stream.Length];

            stream.Read(bytes, 0, (int)stream.Length);

#if !SILVERLIGHT
            text = ASCIIEncoding.ASCII.GetString(bytes);
#endif
            text = Convert.ToBase64String(bytes);

            return text;
        }

        internal static string GetExceptionBytes(Exception ex)
        {
            return GetExceptionBytes(ex, ex.StackTrace);
        }

        internal static string GetExceptionBytes(Exception ex, string stackTrace)
        {
            var settings = new SharpSerializerXmlSettings
            {
                AdvancedSettings = new AdvancedSharpSerializerXmlSettings
                {
                    TypeNameConverter = new TypeNameConverter()
                },

                IncludeAssemblyVersionInTypeName = false,
                IncludeCultureInTypeName = false,
                IncludePublicKeyTokenInTypeName = false
            };

            var serializer = new SharpSerializer(settings);
            var stream = new MemoryStream();
            var text = string.Empty;
            var bytes = (byte[])null;
            var ex2 = new RemotableException(ex);

            if (ex2.StackTrace == null)
            {
                ex2.StackTrace = stackTrace;
            }

            serializer.Serialize(ex2, stream);

            stream.Seek(0, SeekOrigin.Begin);

            bytes = new byte[stream.Length];

            stream.Read(bytes, 0, (int)stream.Length);

#if !SILVERLIGHT
            text = ASCIIEncoding.ASCII.GetString(bytes);
#endif
            text = Convert.ToBase64String(bytes);

            return text;
        }

        internal static void WriteTo(this EventMessage eventMessage, Message message, params object[] parms)
        {
            var stream = new MemoryStream();
            var writer = new BinaryWriter(stream);

            // first int is number of parms

            writer.Write(parms.Length);

            eventMessage.Message = message;

            // order: datatype, length, data



            writer.Flush();

            eventMessage.EventArgs = new byte[(int)stream.Length];

            stream.Seek(0, SeekOrigin.Begin);
            stream.Read(eventMessage.EventArgs, 0, (int)stream.Length);

            writer.Close();
            stream.Close();
        }

        internal static object[] ReadFrom(this EventMessage eventMessage)
        {
            var stream = new MemoryStream(eventMessage.EventArgs.Length);
            var reader = new BinaryReader(stream);
            var count = 0;
            object[] messageObjects;

            stream.Write(eventMessage.EventArgs, 0, eventMessage.EventArgs.Length);
            stream.Seek(0, SeekOrigin.Begin);

            count = reader.ReadInt32();
            messageObjects = new object[count];

            for (var x = 0; x < count; x++)
            {
                var dataType = (DataType)reader.ReadInt32();
                var length = reader.ReadInt32();

                switch (dataType)
                {
                    case DataType.BuildEventArgsType:
                        {
                            var settings = new SharpSerializerXmlSettings
                            {
                                AdvancedSettings = new AdvancedSharpSerializerXmlSettings
                                {
                                    TypeNameConverter = new TypeNameConverter()
                                }
                            };

                            var serializer = new SharpSerializer(settings);
                            var memoryStream = new MemoryStream();
                            var bytes = (byte[])null;
                            var value = reader.ReadString();
                            var streamReader = new StreamReader(memoryStream);

                            bytes = Convert.FromBase64String(value);

                            memoryStream.Write(bytes, 0, bytes.Length);
                            memoryStream.Seek(0, SeekOrigin.Begin);

                            value = streamReader.ReadToEnd();

                            memoryStream.Seek(0, SeekOrigin.Begin);

                            messageObjects[x] = serializer.Deserialize(memoryStream);
                        }

                        break;

                    case DataType.ExceptionType:
                        {
                            var settings = new SharpSerializerXmlSettings
                            { 
                                AdvancedSettings = new AdvancedSharpSerializerXmlSettings
                                {
                                    TypeNameConverter = new TypeNameConverter(),
                                }
                            };

                            var serializer = new SharpSerializer(settings);
                            var memoryStream = new MemoryStream();
                            var bytes = (byte[])null;
                            var value = reader.ReadString();
                            var streamReader = new StreamReader(memoryStream);

                            bytes = Convert.FromBase64String(value);

                            memoryStream.Write(bytes, 0, bytes.Length);
                            memoryStream.Seek(0, SeekOrigin.Begin);

                            value = streamReader.ReadToEnd();

                            memoryStream.Seek(0, SeekOrigin.Begin); 

                            messageObjects[x] = (RemotableException)serializer.Deserialize(memoryStream);
                        } 

                        break;

                    case DataType.StringType:

                        messageObjects[x] = reader.ReadString();
                        break;

                    case DataType.IntegerType:

                        messageObjects[x] = reader.ReadInt32();
                        break;

                    case DataType.FloatType:

                        messageObjects[x] = reader.ReadSingle();
                        break;
                }
            } 

            reader.Close(); 
            stream.Close(); 

            return messageObjects;
        }
    }
}
